package core

import (
	"bou.ke/monkey"
	"encoding/json"
	jsoniter "github.com/json-iterator/go"
	"github.com/shopspring/decimal"
	"log"
	"unsafe"
)

type Qiuya struct {
	Collections *DBMap
}

func InitQiuya(async bool) {
	var err error
	err = snowflake.InitIdWorker(1000, 1)
	if err != nil {
		log.Fatal("无法初始化雪花算法生成器")
	}

	//monkey
	monkey.Patch(json.Marshal, jsoniter.Marshal)
	monkey.Patch(json.Unmarshal, func(data []byte, v interface{}) error {
		var ptr, ok = v.(*interface{})
		if ok {
			return jsoniter.Unmarshal(data, *ptr)
		} else {
			return json.Unmarshal(data, v)
		}
	})
	//
	//jsoniter.

	decodeNumberAsInt64IfPossible := func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
		switch iter.WhatIsNext() {
		case jsoniter.NumberValue:
			var number json.Number
			iter.ReadVal(&number)
			v, err := decimal.NewFromString(number.String())
			if err == nil {
				*(*interface{})(ptr) = v
			}
			break
			//i, err := strconv.ParseInt(string(number), 10, 64)
			//if err == nil {
			//	*(*interface{})(ptr) = i
			//	return
			//}
			//f, err := strconv.ParseFloat(string(number), 64)
			//if err == nil {
			//	*(*interface{})(ptr) = f
			//	return
			//}
			// Not much we can do here.
		default:
			*(*interface{})(ptr) = iter.Read()
		}
	}
	jsoniter.RegisterTypeDecoderFunc("interface {}", decodeNumberAsInt64IfPossible)
	jsoniter.RegisterTypeEncoderFunc("decimal.Decimal", func(ptr unsafe.Pointer, stream *jsoniter.Stream) {
		v := (*decimal.Decimal)(ptr)
		if v.Exponent() == 0 {
			stream.WriteInt64(v.IntPart())
		} else {
			f, _ := v.Float64()
			stream.WriteFloat64Lossy(f)
		}
	}, func(pointer unsafe.Pointer) bool {
		v := (*decimal.Decimal)(pointer)
		return v != nil
	})

	//type  test struct {
	//	Mp *treemap.Map
	//}
	//var t test
	//t.Mp = treemap.NewWith(utils.Int64Comparator)
	//t.Mp.Put(int64(123), "fff")
	//bs,_ := t.Mp.ToJSON()
	////bs,_ := json.Marshal(t)
	//fmt.Println(string(bs))
	//fmt.Println(decimal.NewFromFloat(1.11111).Exponent())
	//var arr []interface{}
	//jsoniter.Unmarshal([]byte(`[1,2,3,4,5]`), &arr)
	//bs, _ := jsoniter.Marshal(arr)
	//
	//fmt.Println(string(bs))
	if DBPath[len(DBPath)-1] == '/' {
		DBPath = DBPath[:len(DBPath)-1]
	}
	qiuya = &Qiuya{
		Collections: NewDBMap(),
	}
	//还原数据
	InitStorage()

	//初始化日志
	InitLog()

	//初始化服务
	InitServer(async)
}

func GetCollection(db, col string) *Collection {
	globalMutex.Lock()
	defer globalMutex.Unlock()
	var ret *Collection
	name := db + "$" + col
	ret = qiuya.Collections.Get(name)
	if ret == nil {
		ret = NewCollection(db, col)
		qiuya.Collections.Put(name, ret)
	}
	return ret
}

func DropDB(db string, log bool) error {
	globalMutex.Lock()
	defer globalMutex.Unlock()
	var keys = []string{}
	var values = []*Collection{}
	for i, v := range qiuya.Collections.Values {
		if v.DBName == db {
			continue
		}
		keys = append(keys, qiuya.Collections.Keys[i])
		values = append(values, v)
	}
	qiuya.Collections.Keys = keys
	qiuya.Collections.Values = values
	if log {
		WriteLog(db, "", ACTION_DROP_DB, nil)
	}
	return nil
}
